// 服务端渲染依赖
import React from 'react';
import ReactDOMServer from 'react-dom/server';
import flushToHTML from 'styled-jsx/server';
import nanoid from 'nanoid';
import { StaticRouter, matchPath } from 'react-router';
import { Provider } from 'react-redux';
import createRouter from '@/client/routes';
import configureStore from '@/client/models/store';
import MetaTagsServer from 'react-meta-tags/server';
import { MetaTagsContext } from 'react-meta-tags';

/**
 * render 中间件
 */
const render = async (ctx, next) => {
    try {
        const store = configureStore();
        let _route = undefined, _match = undefined;
        const router = createRouter({});
        router.routeConfig.some(route => {
            let match = matchPath(ctx.path.split('?')[0], route);
            if(match && match.path) {
                _route = route;
                _match = match;
                return true;
            }
        })
        await next();
        if(_route) {
            let context = { code: 200 };
            if(_route.loadData) {
                context = await _route.loadData({ store });
            }
            await _route.component.preload(); // 预加载
            const _Router = router.dom;
            const metaTagsInstance = MetaTagsServer();
            const nonce = Buffer.from(nanoid()).toString('base64');
            const styles = flushToHTML({ nonce });
            const html = ReactDOMServer.renderToString(
                <Provider store={store}>
                    <MetaTagsContext extract={metaTagsInstance.extract}>
                        <StaticRouter
                            location={ctx.path}
                            context = {context}
                        >
                            <_Router />
                        </StaticRouter>
                    </MetaTagsContext>
                </Provider>
            )
            let meta = metaTagsInstance.renderToString();
            let reduxState = JSON.stringify(store.getState());
            if(context.code === 302) {
                ctx.response.status = 302;
                ctx.response.redirect(context.url); // 重定向
                ctx.body = `Redirecting to ${context.url}`
            } else {
                // 设置 csp 响应头
                ctx.set({
                    'Content-Security-Policy': `default-src 'self' http://localhost:*; style-src 'self' 'nonce-${nonce}'; script-src 'self' http://localhost:* 'nonce-${nonce}';`
                })
                await ctx.render('200', { meta, nonce, styles, html, reduxState  })
            }
        } else {
            console.error(404);
        }
    } catch (e) {
        console.error(500);
        console.error(e);
    }
}

export default render;